"""
Provide the cli to interact with DB through command-line

Usage: sqlbatis [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  **scan**       Show all the models that searched in the directory

  **init**       Init the db tools

  **migrate**    Generate the migrate script

  **upgrade**    Upgrade the db to the version specified, if not sepecified will update to the latest version
  
  **downgrade**: Downgrade the db to the version sepecified, need to give the version parameter
"""
import click
import os
import sys

from mako.template import Template
from sqlbatis.scanner import ModelScanner
from alembic.config import Config
from alembic import command

current_work_dir = os.getcwd()
sys.path.append(current_work_dir)

lib_dir = os.path.abspath(os.path.dirname(__file__))

PREDEFINED_IGNORE_FOLDERS = ['tests', 'build', 'vscode',
                             'dist', 'egg', 'migrations', 'sqlbatis']


@click.group()
def db():
    pass


@db.command()
@click.option('-d', '--directory', default='.', help="""The main folder that you want to search the models,
              default is current work directory""")
@click.option('-i', '--ignore', default=PREDEFINED_IGNORE_FOLDERS, help="""Ignore the folder or files through defined regrex expression, List[regrex]""")
def scan(directory, ignore):
    """Show all the models that searched in the directory
    """
    scanner = ModelScanner(directory, ignore)
    models = scanner.scan_models()
    click.echo(models)


@db.command()
@click.option('-d', '--directory', default='.', help="""The main folder that you want to search the models,
              default is current work directory""")
@click.option('-i', '--ignore', default=PREDEFINED_IGNORE_FOLDERS, help="""Ignore the folder or files through defined regrex expression, List[regrex]""")
@click.option('-db', '--db_url', default='sqlite:///sqlbatis.db', help="""The database url config""")
def init(directory, ignore, db_url):
    """
    Init the db tools
    """
    alembic_cfg = Config('migrations/alembic.ini')
    script_location = os.path.join(current_work_dir, 'migrations')
    command.init(alembic_cfg, script_location)
    _update_alembic_config_file(directory, ignore, db_url)


@db.command()
def migrate():
    """Generate the migrate script
    """
    os.system('alembic -c migrations/alembic.ini revision --autogenerate')


@db.command()
@click.option('-v', '--version', default='head', help="""The version that you want to upgrade to.""")
def upgrade(version):
    """Upgrade the db to the version specified, if not sepecified will update to the latest version
    """
    os.system('alembic -c migrations/alembic.ini upgrade {}'.format(version))


@db.command()
@click.option('-v', '--version', help="""The version that you want to downgrade to.""")
def downgrade(version):
    """Downgrade the db to the version sepecified, need to give the version parameter
    """
    os.system('alembic -c migrations/alembic.ini downgrade {}'.format(version))


def _update_alembic_config_file(directory, ignore, database_url):
    """Update the config file that auto generated by alembic.
    1. alembic.ini
        - Set the sqlachemy.url param
    2. env.py
        - import several packages that defined in the sqlbatis
        - add current work directory to the system path
        - define a func to add all the model in the project to the metadata
        - set the params for the func which are directory and ignore folder

    :param directory: The main search folder
    :type directory: str
    :param ignore: The List of files to ignore
    :type ignore: list(regrex)
    :param database_url: The url of the database
    :type database_url: str
    """
    script_location = os.path.join(current_work_dir, 'migrations')
    alembic_config_templates = os.path.join(
        lib_dir, 'template')
    alembic_ini_template = os.path.join(
        alembic_config_templates, 'alembic.ini.mako')
    alembic_env_template = os.path.join(
        alembic_config_templates, 'env.py.mako')
    alembic_ini = Template(filename=alembic_ini_template).render(
        script_location=script_location, database_url=database_url
    )
    ignore_str = """['{}']""".format("','".join(ignore))
    directory_str = "'{}'".format(directory)
    database_url_str = "'{}'".format(database_url)
    alembic_env = Template(filename=alembic_env_template).render(
        directory=directory_str, ignore=ignore_str, database_url=database_url_str
    )

    with open(os.path.join(script_location, 'alembic.ini'), 'w') as f:
        f.write(alembic_ini)

    with open(os.path.join(script_location, 'env.py'), 'w') as f:
        f.write(alembic_env)


if __name__ == '__main__':
    db()
